﻿/*
 * endian.h
 */
#ifndef __GDK_ENDIAN_H__
#define __GDK_ENDIAN_H__

#include <gdk/core/Types.h>
#include <utility>
#include <algorithm>


namespace gdk
{


//======================================================
#ifndef __GDK_CHECK_ENDIAN___
#define __GDK_CHECK_ENDIAN___

static bool check_endian(void)
{
	uint16_t i = 0x1234;

#if defined(__LITTLE_ENDIAN__)
	if ((*(char*)&i) != 0x34)
#else //__BIG_ENDIAN__
	if ((*(char*)&i) != 0x12)
#endif
	{

#if defined(_MSC_VER)

		__debugbreak();

#elif defined(__ANDROID__)

		__asm__ __volatile__
		(
			"bkpt #3"
		);

#elif defined(__IOS__)


#else

		__asm__ __volatile__
		(
			"int $0x03"
		);

#endif
	}

	return true;
}
static bool g_check_endian = (gdk::nothing(&g_check_endian), check_endian());

#endif //__GDK_CHECK_ENDIAN___



	//======================================================
	template<typename Ty> __INLINE__ Ty swapByte2(Ty i)
	{
		uint16_t *p = reinterpret_cast<uint16_t*>(&i);
		(*p) =
		(
			((*p) >> 8) |
			((*p) << 8)
		);
		return i;
	}
	template<typename Ty> __INLINE__ Ty swapByte4(Ty i)
	{
		uint32_t *p = reinterpret_cast<uint32_t*>(&i);
		(*p) =
		(
			(( *p) >> 24) |
			(( *p) << 24) |
			(((*p) >> 8 ) & 0x0000ff00) |
			(((*p) << 8 ) & 0x00ff0000)
		);
		return i;
	}
	template<typename Ty> __INLINE__ Ty swapByte8(Ty i)
	{
		for (int k = 0; k < 4; ++k) {
            std::swap(((char*)&i)[k], ((char*)&i)[7-k]);
		}
		return i;
	}

	__INLINE__ uint8_t swapByte(uint8_t i)
	{
		return i;
	}
	__INLINE__ int8_t swapByte(int8_t i)
	{
		return i;
	}

	__INLINE__ uint16_t swapByte(uint16_t i)
	{
		return swapByte2(i);
	}
	__INLINE__ int16_t swapByte(int16_t i)
	{
		return swapByte2(i);
	}

	__INLINE__ uint32_t swapByte(uint32_t i)
	{
		return swapByte4(i);
	}
	__INLINE__ int32_t swapByte(int32_t i)
	{
		return swapByte4(i);
	}

	/*
	__INLINE__ uint64_t swapByte(uint64_t i)
	{
		return swapByte8(i);
	}
	__INLINE__ int64_t swapByte(int64_t i)
	{
		return swapByte8(i);
	}
	*/

	__INLINE__ long swapByte(long i)
	{
		switch (sizeof(long)) {
		case 8: return swapByte8(i);
		default: break;
		}
		return swapByte4(i);
	}
	__INLINE__ ulong_t swapByte(ulong_t i)
	{
		switch (sizeof(ulong_t)) {
		case 8: return swapByte8(i);
		default: break;
		}
		return swapByte4(i);
	}

	__INLINE__ long long swapByte(long long i)
	{
		return swapByte8(i);
	}
	__INLINE__ unsigned long long swapByte(unsigned long long i)
	{
		return swapByte8(i);
	}

	__INLINE__ char swapByte(char i)
	{
		return i;
	}
	__INLINE__ bool swapByte(bool i)
	{
		return i;
	}
	__INLINE__ float swapByte(float i)
	{
		return swapByte4(i);
	}
	__INLINE__ double swapByte(double i)
	{
		return swapByte8(i);
	}


	//======================================================
#ifdef __LITTLE_ENDIAN__

	template<typename Ty> __INLINE__ Ty hton(Ty i)
	{
		return swapByte(i);
	}
	template<typename Ty> __INLINE__ Ty ntoh(Ty i)
	{
		return swapByte(i);
	}

#else //__BIG_ENDIAN__

	template<typename Ty> __INLINE__ Ty hton(Ty i)
	{
		return i;
	}
	template<typename Ty> __INLINE__ Ty ntoh(Ty i)
	{
		return i;
	}

#endif



}//namespace gdk


#endif //__GDK_ENDIAN_H__
